/*******************************************************************************
 * Copyright (c) Jonathan Buck - jonbuck16@gmail.com
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    jonbuck16@gmail.com - initial API and implementation
 *******************************************************************************/
package net.jonbuck.tassoo.ui.preference;

import net.jonbuck.tassoo.eventmanager.EventManager;
import net.jonbuck.tassoo.eventmanager.EventManagerImpl;
import net.jonbuck.tassoo.eventmanager.events.CategoriesUpdatedEvent;
import net.jonbuck.tassoo.model.Categories;
import net.jonbuck.tassoo.model.Category;
import net.jonbuck.tassoo.model.TassooFactory;
import net.jonbuck.tassoo.model.TassooPackage;
import net.jonbuck.tassoo.model.provider.TassooItemProviderAdapterFactory;
import net.jonbuck.tassoo.model.util.TassooAdapterFactory;
import net.jonbuck.tassoo.persistence.dao.TassooDao;
import net.jonbuck.tassoo.persistence.dao.TassooDaoImpl;
import net.jonbuck.tassoo.persistence.dao.util.TassooDaoHelperUtil;
import net.jonbuck.tassoo.ui.dialog.ReferenceModelDialog;
import net.jonbuck.tassoo.ui.nl.Messages;
import net.jonbuck.tassoo.ui.preference.provider.ReferenceModelDecorator;

import org.apache.commons.lang.StringUtils;
import org.eclipse.emf.ecore.change.util.ChangeRecorder;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.RemoveCommand;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.DecoratingLabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;

/**
 * 
 * 
 * @since 1.0.0
 */
public class CategoriesPreferencePage extends PreferencePage implements IWorkbenchPreferencePage, ISelectionChangedListener {

	private TassooAdapterFactory adapterFactory;

	private Button addButton;

	private TassooDao tassooDao = TassooDaoImpl.getInstance();

	private Button deleteButton;

	private Button editButton;

	private EditingDomain editingDomain;

	private Button setDefaultButton;

	private Table table;

	private Categories categories;

	private Category selectedCategory;

	private ChangeRecorder recorder;

	private EventManager eventManager = EventManagerImpl.getInstance();

	/**
	 * <p>
	 * <b>Default Constructor</b>
	 * </p>
	 */
	public CategoriesPreferencePage() {
		super();
	}

	/**
	 * <p>
	 * <b>Creates the user interface</b>
	 * </p>
	 * 
	 */
	protected Control createContents(Composite parent) {
		Composite contents = new Composite(parent, SWT.NONE);
		GridLayout layout = new GridLayout(2, false);
		layout.marginHeight = layout.marginWidth = 0;
		contents.setLayout(layout);

		table = new Table(contents, SWT.BORDER | SWT.FULL_SELECTION);
		table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		table.addListener(SWT.MeasureItem, new Listener() {
			public void handleEvent(Event event) {
				event.height = 18;
			}
		});

		final TableViewer categoriesViewer = new TableViewer(table);
		categoriesViewer.setComparator(new ViewerComparator());
		categoriesViewer.addSelectionChangedListener(this);
		categoriesViewer.setContentProvider(new AdapterFactoryContentProvider(adapterFactory));
		DecoratingLabelProvider labelProvider = new DecoratingLabelProvider(new AdapterFactoryLabelProvider(adapterFactory),
				new ReferenceModelDecorator());
		categoriesViewer.setLabelProvider(labelProvider);
		if (tassooDao.isLoaded()) {
			recorder = new ChangeRecorder(categories);
			categoriesViewer.setInput(categories);
		}

		Composite buttons = new Composite(contents, SWT.NONE);
		GridData buttonsGridData = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);
		buttonsGridData.widthHint = 80;
		buttons.setLayoutData(buttonsGridData);
		GridLayout buttonsLayout = new GridLayout(1, false);
		buttonsLayout.marginHeight = buttonsLayout.marginWidth = 0;
		buttons.setLayout(buttonsLayout);

		// Add button
		addButton = new Button(buttons, SWT.NONE);
		addButton.setText(Messages.preferencepage_button_title_add);
		addButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
		addButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				ReferenceModelDialog dialog = new ReferenceModelDialog(Display.getDefault().getActiveShell(),
						TassooFactory.eINSTANCE.createCategory(), Messages.referencemodeldialog_addcategory_title,
						Messages.referencemodeldialog_addcategory_message, Messages.referencetype_category);
				if (dialog.open() == IDialogConstants.OK_ID) {
					Category newCategory = (Category) dialog.getModel();
					editingDomain.getCommandStack().flush();
					editingDomain.getCommandStack().execute(
							AddCommand.create(editingDomain, categories, TassooPackage.Literals.CATEGORIES__CATEGORY, newCategory));
					updateCategoryIsDefaultValues(newCategory);
					categoriesViewer.refresh();
					categoriesViewer.setSelection(new StructuredSelection(newCategory));
				}
			}
		});
		addButton.setEnabled(tassooDao.isLoaded());

		// Edit Button
		editButton = new Button(buttons, SWT.NONE);
		editButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
		editButton.setText(Messages.preferencepage_button_title_edit);
		editButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				ChangeRecorder editRecorder = new ChangeRecorder(selectedCategory);
				ReferenceModelDialog dialog = new ReferenceModelDialog(Display.getDefault().getActiveShell(),
						selectedCategory, Messages.referencemodeldialog_editcategory_title,
						Messages.referencemodeldialog_editcategory_message, Messages.referencetype_category, categories
								.getCategory().toArray());
				if (dialog.open() == IDialogConstants.OK_ID) {
					editRecorder.endRecording();
					if (StringUtils.isNotBlank(selectedCategory.getNewValue())) {
						Category newDefaultCategory = TassooDaoHelperUtil.getCategoryByValue(tassooDao,
								selectedCategory.getNewValue());
						newDefaultCategory.setDefault(true);
					}
					updateCategoryIsDefaultValues(selectedCategory);
					categoriesViewer.refresh();
					categoriesViewer.setSelection(new StructuredSelection(selectedCategory));
				} else {
					editRecorder.endRecording().applyAndReverse();
				}
			}
		});
		editButton.setEnabled(tassooDao.isLoaded());

		// Delete Button
		deleteButton = new Button(buttons, SWT.NONE);
		deleteButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
		deleteButton.setText(Messages.preferencepage_button_title_delete);
		deleteButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				int selectionIndex = table.getSelectionIndex();
				if (MessageDialog.openQuestion(Display.getDefault().getActiveShell(),
						Messages.bind(Messages.delete_question, Messages.referencetype_category),
						Messages.bind(Messages.delete_message, Messages.referencetype_category, selectedCategory.getValue()))) {
					editingDomain.getCommandStack().flush();
					editingDomain.getCommandStack().execute(
							RemoveCommand.create(editingDomain, categories, TassooPackage.Literals.CATEGORIES__CATEGORY,
									selectedCategory));
					// TODO Need to check to see whether the category is being
					// used by a task and if it is then we have to re-allocate
					// those tasks to another category.
					categoriesViewer.refresh();
					categoriesViewer.setSelection(new StructuredSelection(selectionIndex - 1 >= 0 ? table.getItem(
							selectionIndex - 1).getData() : table.getItem(selectionIndex).getData()));
				}
			}
		});
		deleteButton.setEnabled(tassooDao.isLoaded());

		// Set Default Button
		setDefaultButton = new Button(buttons, SWT.NONE);
		setDefaultButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		setDefaultButton.setText(Messages.preferencepage_button_title_setdefault);
		setDefaultButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				editingDomain.getCommandStack().flush();
				editingDomain.getCommandStack().execute(
						SetCommand.create(editingDomain, selectedCategory, TassooPackage.Literals.REFERENCE_MODEL__DEFAULT, true));
				updateCategoryIsDefaultValues(selectedCategory);
				categoriesViewer.refresh();
				categoriesViewer.setSelection(new StructuredSelection(selectedCategory));
			}
		});
		setDefaultButton.setEnabled(tassooDao.isLoaded());

		if (tassooDao.isLoaded()) {
			for (Category category : categories.getCategory()) {
				if (category.isDefault()) {
					categoriesViewer.setSelection(new StructuredSelection(category));
				}
			}
		}

		return contents;
	}

	/**
	 * <p>
	 * <b>Initialises the preference page.</b>
	 * </p>
	 */
	public void init(IWorkbench workbench) {
		this.setDescription(Messages.categoriespreferencepage_description);
		this.noDefaultAndApplyButton();
		adapterFactory = new TassooItemProviderAdapterFactory();
		editingDomain = tassooDao.getEditingDomain();
		if (tassooDao.isLoaded()) {
			categories = tassooDao.getCategories();
		}
	}

	/**
	 * <p>
	 * <b>Update the list of preferences.</b>
	 * </p>
	 */
	public boolean performOk() {
		if (tassooDao.isLoaded()) {
			recorder.endRecording();
			eventManager.fireEvent(new CategoriesUpdatedEvent());
		}
		return true;
	}

	/**
	 * 
	 */
	public boolean performCancel() {
		if (tassooDao.isLoaded()) {
			recorder.endRecording().applyAndReverse();
		}
		return true;
	}

	/**
	 * 
	 */
	public void selectionChanged(SelectionChangedEvent event) {
		IStructuredSelection selection = (IStructuredSelection) event.getSelection();
		selectedCategory = (Category) selection.getFirstElement();
		if (selectedCategory != null) {
			if (categories.getCategory().size() == 1) {
				deleteButton.setEnabled(false);
				setDefaultButton.setEnabled(false);
			} else {
				if (selectedCategory.isDefault()) {
					deleteButton.setEnabled(false);
					setDefaultButton.setEnabled(false);
				} else {
					deleteButton.setEnabled(true);
					setDefaultButton.setEnabled(true);
				}
			}
		}
	}

	/**
	 * 
	 * @param updatedCategory
	 */
	private void updateCategoryIsDefaultValues(Category updatedCategory) {
		if (updatedCategory.isDefault()) {
			for (Category tempCategory : categories.getCategory()) {
				if (tempCategory != updatedCategory) {
					editingDomain.getCommandStack().execute(
							SetCommand.create(editingDomain, tempCategory, TassooPackage.Literals.REFERENCE_MODEL__DEFAULT, false));
				}
			}
		}
	}

}
